package com.bt.lms.ui.action.divide.plan;

import com.alibaba.fastjson.JSON;
import com.bt.lms.constants.ClassBizTypeConstant;
import com.bt.lms.ui.action.divide.plan.vo.RandomDivideVo;
import com.bt.lms.constants.BOConstant;
import com.bt.lms.network.msg.ReqMsg;
import com.bt.lms.network.msg.packet.ReqMsgPacket;
import com.bt.lms.ui.page.common.action.pagerecord.SeparateClassLabAction;
import com.bt.lms.ui.page.classes.PreviewShiftResult;
import com.bt.lms.ui.page.classes.PageRandomShift;
import com.bt.lms.utils.Convert;
import javafx.collections.ObservableList;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.control.Alert;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * 随机平均分班预览分班结果事件
 */
public class PreviewResultsBtnAction implements EventHandler {

    private PageRandomShift pageRandomShift; //随机平均分班页面

    private List<HBox> list;

    public PreviewResultsBtnAction(PageRandomShift pageRandomShift, List list) {
        this.pageRandomShift = pageRandomShift; //维护界面
        this.list = list;
    }


    @Override
    public void handle(Event event) {

        //1.获取用户输入，返回VO：里面承载着用户的输入
        RandomDivideVo randomDivideVo = getInParams();
        //2.验证用户输入，inP:VO outP:消息
        String validateMsg = validateInParam(randomDivideVo);
        //3.组包（根据自定义的网络消息协议），inP:VO outP:消息
        ReqMsg reqMsg = null;
        if (null == validateMsg) {

            //验证通过，组包
            reqMsg = handle2ReqMsg(randomDivideVo);

        } else {
            //提示，程序终止
            return;
        }
        //消息转为消息包
        ReqMsgPacket reqMsgPacket = encode(reqMsg);

        //4.组网（根据咱们自定义的网络连接交互规范来定义）inP:服务器的信息（ip,port....）
        Socket socket = getNet();
        //5.发送消息，inP:消息 ouP:是否发送成熟
        boolean flag = send(socket, reqMsgPacket);

        PreviewShiftResult previewShiftResult = new PreviewShiftResult();
        Pane pane = SeparateClassLabAction.pageSkipInfo.getPane();
        Integer index = SeparateClassLabAction.pageSkipInfo.getIndex();
        pane.getChildren().set(index, previewShiftResult);
    }

    /**
     * 发送信息
     * 1.将消息包转为字节流
     * 2.发送
     *
     * @param socket       发送的socket
     * @param reqMsgPacket 要发送的消息包
     * @return
     */
    private boolean send(Socket socket, ReqMsgPacket reqMsgPacket) {
        //发送
        //数据长度
        byte[] dataLen = reqMsgPacket.getDataLen();
        int dataLength = dataLen.length; //数据长度
        byte[] totalLength = new byte[ReqMsg.MSG_HEAD_LENGTH + dataLength]; //总长度 = 消息头长度+数据长度

        byte[] magicNo = reqMsgPacket.getMagicNo();//魔数
        System.arraycopy(magicNo, 0, totalLength, 0, 12);
        byte versions = reqMsgPacket.getVersion();//协议版本号
        totalLength[12] = versions;
        byte serialCou = reqMsgPacket.getSerialCou();//序列化算法
        totalLength[13] = serialCou;
        byte incidentType = reqMsgPacket.getEvenType();//事件类型
        totalLength[14] = incidentType;
        byte[] busType = reqMsgPacket.getBizType();//业务类型
        System.arraycopy(busType, 0, totalLength, 15, 2);
        Byte twoWay = reqMsgPacket.getTwoWay();//2Way
        totalLength[17] = twoWay;
        byte[] requestId = reqMsgPacket.getReqID();//请求id
        System.arraycopy(requestId, 0, totalLength, 18, 8);
        byte[] retainField = reqMsgPacket.getRemainField();//保留字段
        System.arraycopy(retainField, 0, totalLength, 26, 16);
        //数据长度
        System.arraycopy(dataLen, 0, totalLength, 42, dataLength);

        //消息体
        byte[] msgBody = reqMsgPacket.getData();
        int msgBodyLength = msgBody.length;
        System.arraycopy(dataLen, 0, totalLength, 46, msgBodyLength);

        try {
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write(totalLength);
            outputStream.flush();//冲刷
            //关流
            outputStream.close();
            socket.close();

        } catch (IOException e) {
//            throw new RuntimeException(e);
        }
        return true;
    }

    /**
     * 将消息对象变成  字节数组
     *
     * @param reqMsg 请求消息
     * @return
     */
    private ReqMsgPacket encode(ReqMsg reqMsg) {
        //组包，请求方向
        //消息头，功能类型，2字节 1001
        //消息头
        ReqMsgPacket reqMsgPacket = new ReqMsgPacket();

        //协议版本号
        Byte version = reqMsg.getVersion();
        reqMsgPacket.setVersion(version);
        //序列化算法
        Byte serialCou = reqMsg.getSerialCou();
        reqMsgPacket.setSerialCou(serialCou);
        //事件类型
        Byte evenType = reqMsg.getEvenType();
        reqMsgPacket.setEvenType(evenType);
        //业务类型
        Short busType = reqMsg.getBizType();
        byte[] busTypeBytes = Convert.shortToBytes(busType);
        reqMsgPacket.setBizType(busTypeBytes);
        //2Way
        Byte twoWay = reqMsg.getTwoWay();
        reqMsgPacket.setTwoWay(twoWay);
        //请求id 时间戳
        Long reqID = reqMsg.getReqId();
        byte[] reqIDBytes = Convert.longToBytes(reqID);
        reqMsgPacket.setReqID(reqIDBytes);
        //保留字段
        byte[] remainField = reqMsg.getRemainField();
        reqMsgPacket.setRemainField(remainField);

        //消息体
        String data = reqMsg.getData();
        byte[] dataBytes = data.getBytes();
        reqMsgPacket.setData(dataBytes);


        return reqMsgPacket;
    }

    /**
     * 将int数值转换成占四个字节的byte数组，本方法适用于（高位在前，低位在后）的顺序
     * 和 bytesToInt2() 配套使用
     *
     * @param value
     * @return
     */
    private byte[] intToBytes(int value) {
        byte[] src = new byte[4];
        src[0] = (byte) ((value >> 24) & 0xFF);
        src[1] = (byte) ((value >> 16) & 0xFF);
        src[2] = (byte) ((value >> 8) & 0xFF);
        src[3] = (byte) (value & 0xFF);
        return src;
    }

    /**
     * 获取网络
     *
     * @return socket
     */
    private Socket getNet() {
        String serverIp = "127.0.0.1";
        int serverPort = 8888;
        Socket socket = null;

        try {
            socket = new Socket(serverIp, serverPort);
        } catch (IOException e) {
//            throw new RuntimeException(e);
            return null;
        }

        return socket;
    }

    /**
     * 将用户输入的信息处理成我们规定的请求信息
     *
     * @param randomDivideVo 用户输入
     * @return 请求消息
     */
    private ReqMsg handle2ReqMsg(RandomDivideVo randomDivideVo) {

        //消息头
        ReqMsg reqMsg = new ReqMsg();
        //魔数
        reqMsg.setMagicNo(ReqMsg.NETWORK_MAGIC_NO);
        //业务类型
        reqMsg.setBizType(ClassBizTypeConstant.DIVIDE_PLAN_PREVIEW_RESULT);
        //请求id（事件戳）
        long time = System.currentTimeMillis();
        reqMsg.setReqId(time);

        //消息体
        //数据
        //将对象转成json对象
        String classStr = JSON.toJSONString(randomDivideVo);
        reqMsg.setData(classStr);


        return reqMsg;
    }

    /**
     * 验证用户的输入是否符合条件
     *
     * @param randomDivideVo 用户的输入信息
     * @return 验证消息
     */
    private String validateInParam(RandomDivideVo randomDivideVo) {
        String msg = ""; //所有提示信息
        //分班数
        String shiftsNumber = randomDivideVo.getShiftsNumber();
        String numberBlankMsg = "分班数必须填写！\r\n";
        String numberLengthMsg = "分班数必须大于1且小于350！\r\n";
        String numberFormat = "分班数必须填写数字\r\n";
        if ("".equals(shiftsNumber)) {
            msg += numberBlankMsg;
        } else {
            try {
                int i = Integer.parseInt(shiftsNumber);
                if (i > 350 || i < 1) {
                    msg += numberLengthMsg;
                }
            } catch (NumberFormatException e) {
                msg += numberFormat;
            }
        }

        //班ID
        String iDBlankMsg = "班级ID必须填写！\r\n";
        if (randomDivideVo.getClassID() != null && !"".equals(randomDivideVo.getClassID())) {
            int p = 0;

            List<String> classID = randomDivideVo.getClassID();

            for (String s : classID) {
                p++;
                String iDLengthMsg = "第\"" + p + "\"次的班级ID长度超过了18位，请重新输入\r\n";
                if (s.length() > 18) {
                    msg += iDLengthMsg;

                }

            }
        } else {
            msg += iDBlankMsg;
        }

        //班级名称
        String nameBlankMsg = "班级名称必须填写！\r\n";
        if (randomDivideVo.getName() != null && !"".equals(randomDivideVo.getName())) {
            int p = 0;

            List<String> className = randomDivideVo.getName();
            for (String s : className) {
                p++;
                String nameLengthMsg = "第\"" + p + "\"次的班级名称长度超过了18位，请重新输入\r\n";
                if (s.length() > 18) {
                    msg += nameLengthMsg;
                }
            }
        } else {
            msg += nameBlankMsg;
        }

        //随机生成人数
        String stuNoBlankMsg = "请填写人数分配结果！\n";
        if (randomDivideVo.getStuNo() == null) {
            msg += stuNoBlankMsg;
        } else {
            List<Integer> stuNo = randomDivideVo.getStuNo();
            Integer integer = stuNo.get(0);
            if (integer != null) {
                int p = 0;


                for (Integer s : stuNo) {
                    p++;
                    String nameLengthMsg = "第\"" + p + "\"次的学员人数必须大于1且小于350\r\n";
                    if (s > 350) {
                        msg += nameLengthMsg;
                    }
                }
            }

        }

        //字符串转null
        if (msg.equals("")) {
            msg = null;
        }

        if (!(msg == null)) {
            Alert alert = new Alert(Alert.AlertType.WARNING);
            alert.setContentText(msg);
            alert.show();
        }
        return msg;
    }

    /**
     * 获取用户输入
     *
     * @return 输入的信息
     */
    private RandomDivideVo getInParams() {

        RandomDivideVo randomDivideVo = new RandomDivideVo();

        //填写分班数
        TextField writeTF = (TextField) pageRandomShift.lookup("#writeTF");
        String divide = writeTF.getText().trim();
        randomDivideVo.setShiftsNumber(divide);

        List<String> idList = new ArrayList<>();
        List<String> nameList = new ArrayList<>();
        List<Integer> stuNoList = new ArrayList<>();
        if (list.size() <= 1) {
            for (HBox ignored : list) {
                ObservableList<Node> children = ignored.getChildren();
                TextField textField = (TextField) children.get(0);
                String idStr = textField.getText().trim();

                TextField textField1 = (TextField) children.get(1);
                String nameStr = textField1.getText().trim();

                TextField textField2 = (TextField) children.get(2);
                String stuNo = textField2.getText().trim();
                Integer integer = null;
                try {
                    integer = Integer.valueOf(stuNo);
                } catch (NumberFormatException e) {
//            throw new RuntimeException(e);
                }
                if (!idStr.equals("")) {
                    idList.add(idStr);
                    randomDivideVo.setClassID(idList);
                }
                if (!nameStr.equals("")) {
                    nameList.add(nameStr);
                    randomDivideVo.setName(nameList);
                }
                if (integer != null) {
                    stuNoList.add(integer);
                    randomDivideVo.setStuNo(stuNoList);
                }

            }
        } else  {
            for (HBox ignored : list) {
                ObservableList<Node> children = ignored.getChildren();
                TextField textField = (TextField) children.get(0);
                String idStr = textField.getText().trim();

                TextField textField1 = (TextField) children.get(1);
                String nameStr = textField1.getText().trim();

                TextField textField2 = (TextField) children.get(2);
                String stuNo = textField2.getText().trim();
                Integer integer = null;
                try {
                    integer = Integer.valueOf(stuNo);
                } catch (NumberFormatException e) {
//            throw new RuntimeException(e);
                }

                idList.add(idStr);
                randomDivideVo.setClassID(idList);


                nameList.add(nameStr);
                randomDivideVo.setName(nameList);


                stuNoList.add(integer);
                randomDivideVo.setStuNo(stuNoList);

            }
        }


        return randomDivideVo;
    }


    public PageRandomShift getPageRandomShift() {
        return pageRandomShift;
    }

    public void setPageRandomShift(PageRandomShift pageRandomShift) {
        this.pageRandomShift = pageRandomShift;
    }
}
